﻿using System;
using System.Xml;
using System.Xml.XPath;

namespace Songhay.Data
{
    using Songhay.Xml;

    public partial class DataAccessItem
    {
        /// <summary>
        /// Returns the first <see cref="Songhay.Data.DataAccessItem"/>
        /// in the configuration.
        /// </summary>
        public Connection GetFirstConnection()
        {
            Connection cnnInfo = (!FrameworkType.ArrayIsNullOrEmptyOrNotArray(this.Connection)) ? this.Connection[0] : null;
            return cnnInfo;
        }

        /// <summary>
        /// Returns the first <see cref="Songhay.Data.NameValuePair"/>
        /// in the configuration.
        /// </summary>
        public NameValuePair GetFirstNameValuePair()
        {
            NameValuePair nvp = (!FrameworkType.ArrayIsNullOrEmptyOrNotArray(this.NameValuePair)) ? this.NameValuePair[0] : null;
            return nvp;
        }

        /// <summary>
        /// Returns a <see cref="Songhay.Data.Connection"/>
        /// by searching based on the specified array and key.
        /// </summary>
        /// <param name="key">
        /// The key corresponding to <see cref="Songhay.Data.Connection.Name"/>.
        /// </param>
        public Connection GetConnection(String key)
        {
            if(this.Connection == null) return null;
            return Array.Find(this.Connection,
                delegate(Connection cnn) { return cnn.Name == key; });
        }

        /// <summary>
        /// Returns a <see cref="Songhay.Data.NameValuePair"/>
        /// by searching based on the specified key.
        /// </summary>
        /// <param name="key">
        /// The key corresponding to <see cref="Songhay.Data.Connection.Name"/>.
        /// </param>
        public NameValuePair GetNameValuePair(string key)
        {
            if(this.NameValuePair == null) return null;
            return Array.Find(this.NameValuePair,
                delegate(NameValuePair nvp) { return nvp.Name == key; });
        }

        /// <summary>
        /// Attempts to find and return the value from a
        /// <see cref="Songhay.Data.NameValuePair"/>
        /// based on the specified key.
        /// </summary>
        /// <param name="key">The key in the array of pairs.</param>
        /// <returns>
        /// Return the value (or <c>null</c>) from a
        /// <see cref="Songhay.Data.NameValuePair"/>
        /// based on the specified key.
        /// </returns>
        public string GetNameValuePairValue(string key)
        {
            return GetNameValuePairValue(key, false);
        }

        /// <summary>
        /// Attempts to find and return the value from a
        /// <see cref="Songhay.Data.NameValuePair"/>
        /// based on the specified key.
        /// </summary>
        /// <param name="key">The key in the array of pairs.</param>
        /// <param name="throwException">
        /// When <c>true</c> throw an exception for pairs not found.
        /// </param>
        /// <returns>
        /// Return the value from a
        /// <see cref="Songhay.Data.NameValuePair"/>
        /// based on the specified key.
        /// </returns>
        public string GetNameValuePairValue(string key, bool throwException)
        {
            NameValuePair nvp = this.GetNameValuePair(key);
            if(throwException && (nvp == null))
            {
                throw new DataAccessConfigurationException("NameValuePair", string.Format("A Name-Value pair was not found with key “{0}”", key));
            }
            else if(nvp == null)
            {
                return null;
            }
            else
            {
                return nvp.Value;
            }
        }
    }

    public partial class DataAccessConfiguration
    {
        /// <summary>
        /// Default constructor.
        /// </summary>
        public DataAccessConfiguration() { }

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="xmlPath">
        /// Path to XML file based on the schema of this class.
        /// </param>
        public DataAccessConfiguration(String xmlPath)
        {
            XPathDocument x = new XPathDocument(xmlPath);

            string rawXml = x.CreateNavigator().OuterXml;

            DataAccessConfiguration that = XmlUtility.GetInstanceRaw<DataAccessConfiguration>(rawXml);
            this.dataAccessItemField = that.dataAccessItemField;
        }

        /// <summary>
        /// Returns a <see cref="Songhay.Data.DataAccessItem"/>
        /// by searching based on the specified name.
        /// </summary>
        /// <param name="name">
        /// The key corresponding to <see cref="Songhay.Data.DataAccessItem.Name"/>.
        /// </param>
        public DataAccessItem GetDataAccessItem(String name)
        {
            return Array.Find(this.dataAccessItemField,
                delegate(DataAccessItem dbInfo) { return dbInfo.Name == name; });
        }

        /// <summary>
        /// Returns <see cref="Songhay.Data.DataAccessItem"/>
        /// data based on the XML file path and the dataQuery expression.
        /// </summary>
        /// <param name="xmlPath">the XML file path</param>
        /// <param name="dataQuery">the dataQuery expression</param>
        public static DataAccessItem GetDataAccessItem(String xmlPath, String dataQuery)
        {
            XPathDocument x = new XPathDocument(xmlPath);
            XmlNamespaceManager nsman = XmlUtility.GetNamespaceManager(x);
            XPathNavigator node = XmlUtility.GetNavigableNode(x, dataQuery, nsman);
            if(node == null) throw new Exception(String.Format("Cannot find Data Activity at “{0}.”", dataQuery));

            return XmlUtility.GetInstanceRaw<DataAccessItem>(node.OuterXml);
        }
    }
}
